import events from "events";
import { checkOptions } from "@/utils/common";
import { v4 as uuidv4 } from "uuid";

export class BasicComponents extends events.EventEmitter {
  protected container: HTMLElement | string // 容器
  protected viewMap: Map<string, any> // 实例

  constructor(options: any) {
    super();
    const checkedOptions = checkOptions(options, [
      { key: "container", require: true},
    ]);
    this.viewMap = new Map();
    this.container = checkedOptions.container;
  }

  /**
   * 抛出错误
   * @param {string} path // 报错文件
   * @param {string} description // 报错描述
   */
  private __throwError__(path: string, description: string) {
    let errorMsg = {
      msg: `${path} : ${description}`
    };
    this.emit("commonError", {
      path,
      description,
    });
    throw new Error(JSON.stringify(errorMsg));
  }

  /**
   * 创建DOM
   * @param {object} component Vue实例
   * @description 返回的Vue中被注入__viewId，可通过__viewId访问和销毁实例
   * @returns component
   */
  public createComponent(component: any) {
    const id = uuidv4();
    // 创建容器
    const divDom = document.createElement("div");
    divDom.id = id;
    if (typeof this.container === 'string') {
      document.getElementById(this.container)?.appendChild(divDom);
    } else {
      this.container?.appendChild(divDom);
    }
    component.__viewId = id;
    component.$mount(divDom);
    this.viewMap && this.viewMap.set(id, component);
    this.emit("load", component);
    return component;
  }

  /**
   * 销毁DOM 为空则销毁所有面板
   * @param {string[]} viewIds
   */
  public removeComponents(viewIds: Array<string>) {
    if (Array.isArray(viewIds)) {
      viewIds.forEach((viewId) => {
        if (this.viewMap?.has(viewId)) {
          const component = this.viewMap.get(viewId);
          component.$el.remove();
          component.$destroy();
          this.viewMap.delete(viewId);
        }
      })
    } else {
      this.viewMap?.forEach((component) => {
        component.$el.remove();
        component.$destroy();
        if (this.container) {
          if (typeof this.container === "string") {
            let container = document.getElementById(this.container);
            container?.parentNode?.removeChild(container);
          } else {
            this.container.parentNode?.removeChild(this.container);
          }
        }
      });
      this.viewMap?.clear();
    }
    this.emit("removeComponents", viewIds);
  } 

  /**
   * 面板显示隐藏切换， 为空则隐藏所有
   * @param {string[]} viewIds 隐藏的 component id
   * @param {boolean} visible 是否隐藏
   */
  private __changeComponentVisible__(viewIds: Array<string>, visible: boolean) {
    // 指定viewIds
    if (Array.isArray(viewIds)) {
      viewIds.forEach((viewId) => {
        if (this.viewMap.has(viewId)) {
          const component = this.viewMap.get(viewId);
          component.$el.style.display = visible ? "" : "none";
        } else {
          this.__throwError__("basicComponent => __changeComponentVisible", `不存在${viewId}面板`);
        }
      });
    } else {
      // 全部
      this.viewMap.forEach((component) => {
        if (this.viewMap.get(component.__viewId)) {
          component.$el.style.display = visible ? "" : "none";
        } else {
          this.__throwError__("basicComponent => __changeComponentVisible", `不存在${component.__viewId}面板`);
        }
      })
    }
  }

  /**
   * 显示面板 为空则显示所有
   * @param {string[]} viewIds 需要显示的面板ids
   */
  public showComponents(viewIds: Array<string>) {
    this.__changeComponentVisible__(viewIds, true);
    this.emit("showComponent", {
      viewIds,
    });
  }

  /**
   * 隐藏面板 为空则隐藏所有面板
   * @param {string[]} viewIds 需要隐藏的面板ids
   */
  public hideComponents(viewIds: Array<string>) {
    this.__changeComponentVisible__(viewIds, false);
    this.emit("hideComponents", {
      viewIds,
    });
  }
}